package com.nxy.cpfsfe.busi.bolag;



import com.adtec.starring.datapool.CompSDO;
import com.adtec.starring.datapool.EPOper;
import com.adtec.starring.exception.BaseException;
import com.adtec.starring.struct.dta.DtaInfo;
import com.adtec.starring.util.SpringUtil;
import com.nxy.cpfsfe.busi.btmgtsk.BatchSettlementProc;
import com.nxy.cpfsfe.enumtype.*;
import com.nxy.cpfsfe.mybatis.mapper.TbAMapper;
import com.nxy.cpfsfe.mybatis.mapper.TsPCmdMapper;
import com.nxy.cpfsfe.service.CpfsService;
import com.nxy.cpfsfe.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.sql.SQLException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


/**
 * NCS往账
 * @author nxygyzd
 *
 */


public class NCSNstrASrvBean implements CpfsService {
	
	private final static Logger LOGGER = LoggerFactory.getLogger(NCSNstrASrvBean.class);	
	SqlSession sqlSession = null;	
	private String resCd = RespCd.NCPI0000;

		
	
	/**
	 * 异步处理
	 * NCS往账服务
	 */
	public void doService() {
		
		String tpId = DtaInfo.getInstance().getTpId();
		// 获取输入
		CompSDO inputSdo = (CompSDO) EPOper.getCompSDO(tpId, "ReqBody"); // 获取输入接口
		String bizMsg = (String) inputSdo.getValue("BizMsg")!=null?(String) inputSdo.getValue("BizMsg"):"";
		LOGGER.info("接收到输入BizMsg报文数据：[{}]",bizMsg);
		String sndAppCd = (String) EPOper.get(tpId, "ReqBean[0].head[0].sndAppCd");
		//数据入库和调网关服务操作
		nCSFeToGW(bizMsg,sndAppCd);
	}
	

	/**
	 *
	 * Description:NPS.120.001.01、NPS.140.001.01、NPS.142.001.01-登记账务流水和业务流水
	 * 登记成功，往NCS发业务报文，登记失败，往业务系统返回911 报文
	 * @author
	 * @data 2019年8月24日 
	 * @param bizMsg 报文字符串
	 * @param sndAppCd 发起方系统编号
	 * 
	 */
	public void regBizSeqAndAgSeq(String bizMsg,String sndAppCd) {
		Map map = null;
		try {
			//解析报文
			map = xml2BizMap(bizMsg,sndAppCd);
			sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");
			TsPCmdMapper tsPCmd = sqlSession.getMapper(TsPCmdMapper.class);
			TbAMapper tbAMapper = sqlSession.getMapper(TbAMapper.class);
            int resultCmdNum = 0;
            int resultTbANum = 0;
            if(TAbEnum.DrcrFlag_C.getCode().equals(map.get("drcrFlg"))){     //贷记
				//插入数据支付流水表TsPCmd和插入数据业务流水表TbA
                resultCmdNum = tsPCmd.insertCdtByMap(map);
                if(resultCmdNum != 1){
                    throw new BaseException(RespCd.NCPS5002,"支付流水插入失败");
                }
                resultTbANum = tbAMapper.insertCdtByMap(map);
                if(resultTbANum != 1){
                    throw new BaseException(RespCd.NCPS5002,"账务流水插入失败");
                }
			}else if (TAbEnum.DrcrFlag_D.getCode().equals(map.get("drcrFlg"))) {   //借记
				//插入数据支付流水表TsPCmd和插入数据业务流水表TbA
                resultCmdNum = tsPCmd.insertDrctByMap(map);
                if(resultCmdNum != 1){
                    throw new BaseException(RespCd.NCPS5002,"支付流水插入失败");
                }
                resultTbANum = tbAMapper.insertDrctByMap(map);
                if(resultTbANum != 1){
                    throw new BaseException(RespCd.NCPS5002,"账务流水插入失败");
                }
			}
			LOGGER.info("报文标识号chlSeqNo=[{}]，业务流水表TbA和支付流水表TsPCmd入库成功",map.get("chlSeqNo"));
		}catch(DataAccessException e){
			LOGGER.error("报文标识号chlSeqNo=[{"+map.get("chlSeqNo")+"}] 插入数据失败：业务流水表TbA或支付流水表TsPCmd;错误栈",e);
			int a =((SQLException) e.getCause()).getErrorCode();
			DBErrorCdEnum dberr = DBErrorCdEnum.getEnum(a+"");
			throw new BaseException(dberr.getName(),e,"流水号["+map.get("chlSeqNo")+"],"+dberr.getDesc());
		} catch (Throwable e) {
			throw e;
		}
	}


	/**
	 * 判断需异步发往网关业务报文还是911报文
	 * @param bizMsg
	 * @param sndAppCd
	 */
	 public void nCSFeToGW(String bizMsg,String sndAppCd) {
		 boolean bool = false;
		 Map<String, Object> maperr = new HashMap<String, Object>();
		 try {
			 //登记流水表
			 regBizSeqAndAgSeq(bizMsg, sndAppCd);
			 bool = true;
		} catch (BaseException e) {
			maperr.put("PrcCd",e.getErrorCode());
			maperr.put("RjctInf",e.getErrorDesc());			
			LOGGER.error("登记流水失败,错误信息",e);

		}catch (Throwable e) {
			LOGGER.error("登记流水失败",e);
			maperr.put("PrcCd",RespCd.NCPO0009);
			maperr.put("RjctInf","未知错误，本报文被丢弃");	
		}
		 
		 String tpId = DtaInfo.getInstance().getTpId();
		 String msgId="";
		 try {
			 msgId = StringUtils.isBlank(XmlUtil.getValByXPath(bizMsg,"/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId")) ? XmlUtil.getValByXPath(bizMsg,"/transaction/body/FIToFICstmrDrctDbt/GrpHdr/MsgId"):XmlUtil.getValByXPath(bizMsg,"/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId");
			 if (bool) {
				 //发NCS往账报文,若是批量CPFS发起的120 需修改TdBatchAEnum表业务状态
				 if (SysEcodeEnum.CPFS.getCode().equals(sndAppCd)) {
				 	 String  acqOrgId = StringUtil.trimObject(XmlUtil.getValByXPath(bizMsg, "/transaction/header/msg/sndMbrCd"));
					 LOGGER.info("更新批量交易MsgId=[{}],业务状态：[{}]", msgId, TdBatchAEnum.StlSta_ING.getCode());
					 String trxId = XmlUtil.getValByXPath(bizMsg,"/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/PmtId/EndToEndId");
					 BatchSettlementProc.getInstance().updateTdBatchAStlSta(acqOrgId,msgId, trxId,TdBatchAEnum.StlSta_ING.getCode(),"");
					 //批量发起的initrSeqno取报文标识号；从业务系统来的沿用GW送的initrSeqno值，可以从上下文取到不需要设置
					 EPOper.put(tpId, "ReqBean[0].head[0].initrSeqno", msgId);
				 }
				 EPOper.put(tpId, "ReqBean[0].head[0].sndAppCd", sndAppCd);
				 EPOper.put(tpId, "ReqBean[0].head[0].reqServCd", XmlUtil.getValByXPath(bizMsg, "/transaction/header/msg/msgCd"));
				 EPOper.put(tpId, "ReqBean[0].head[0].rcvAppCd", SysEcodeEnum.NCS.getCode());
				 EPOper.getCompSDO(tpId, "ReqBody").setValue("BizMsg", bizMsg);
				 resCd = RpcCommUtil.getInstance().rpcFeToGW(tpId, RpcOutputInfoEnum.OutputName_Pub_Cpfsgw.getCode(), RpcOutputInfoEnum.OutPutSvr_CpfsFwdThrdPrtS.getCode());
				 //LOGGER.info("往账调用网关返回码：resCd=[{}]", resCd);
				
			 } else {
				 //发911报文,CPFS批量交易120不需要更新状态
				 if (!SysEcodeEnum.CPFS.getCode().equals(sndAppCd)) {
					 Map map911 = xml2BizMap(bizMsg, sndAppCd);
					 map911.putAll(maperr);
					 bizMsg = ResponseUtil.build911Xml(map911);					
					 //从业务系统来的沿用GW送的initrSeqno值，可以从上下文取到不需要设置
					 EPOper.put(tpId, "ReqBean[0].head[0].sndAppCd", sndAppCd);
					 EPOper.put(tpId, "ReqBean[0].head[0].rcvAppCd", sndAppCd);
					 EPOper.put(tpId, "ReqBean[0].head[0].reqServCd", MsgCdOrTpEnum.MSGCD_911.getCode());
					 EPOper.getCompSDO(tpId, "ReqBody").setValue("BizMsg", bizMsg);
					 resCd = RpcCommUtil.getInstance().rpcFeToGW(tpId, RpcOutputInfoEnum.OutputName_Pub_Cpfsgw.getCode(), RpcOutputInfoEnum.OutPutSvr_CpfsFwdThrdPrtS.getCode());
					 LOGGER.info("发911 报文返回码resCd=[{}]", resCd);
				 }else {
					 String  acqOrgId = StringUtil.trimObject(XmlUtil.getValByXPath(bizMsg, "/transaction/header/msg/sndMbrCd"));
					 LOGGER.info("更新批量交易MsgId=[{}],业务状态：[{}]", msgId, TdBatchAEnum.StlSta_Fail.getCode());
					 String trxId = XmlUtil.getValByXPath(bizMsg,"/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/PmtId/EndToEndId");
					 BatchSettlementProc.getInstance().updateTdBatchAStlSta(acqOrgId,msgId, trxId,TdBatchAEnum.StlSta_Fail.getCode(),(String)maperr.get("RjctInf"));

				 }
			 }
		 }catch (Throwable e){
			 LOGGER.error("往账发往网关nCSFeToGW方法异常msgId=["+msgId+"]", e);
		 }
	}
	 
	
	
	
	
	/**
	 * 解析报文并做特殊处理
	 * @param bizMsg
	 * @param sndAppCd
	 * @return
	 */
	public Map xml2BizMap (String bizMsg,String sndAppCd){
		Map<String, Object> map =null;
		try{
			//拆解xml报文为xml2BizMap
			Map xml2BizMap = XmlUtil.xml2Map(bizMsg);
			//把map1<String, String>转换成map<String, Object>
			map = xml2BizMap;
			//格式化Ustrd标签下的值
			map = XmlUtil.formatXmlAttr(map,"Ustrd");
			//借记和贷记报文结构不一样
			String drcrFlg = StringUtils.isNotEmpty((String) map.get("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/PmtTpInf/CtgyPurp/Prtry") ) ? (String) map.get("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/PmtTpInf/CtgyPurp/Prtry"):(String) map.get("/transaction/body/FIToFICstmrDrctDbt/GrpHdr/PmtTpInf/LclInstrm/Prtry");
			drcrFlg = drcrFlg != null ? drcrFlg.toString() : "";
			String pInfo="";
			if(drcrFlg.startsWith("A")||drcrFlg.startsWith("C")){
				drcrFlg=TAbEnum.DrcrFlag_C.getCode();//贷记
				pInfo=XmlUtil.getXmlByXPath(bizMsg, "/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/RmtInf").replaceAll(" ", "");
				map.put("reserved1",(String) map.get("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/RmtInf/Remark"));
			}else if (drcrFlg.startsWith("B")||drcrFlg.startsWith("D")){
				drcrFlg=TAbEnum.DrcrFlag_D.getCode();//借记
				pInfo=XmlUtil.getXmlByXPath(bizMsg, "/transaction/body/FIToFICstmrDrctDbt/DrctDbtTxInf/RmtInf").replaceAll(" ", "");
				map.put("reserved1",(String) map.get("/transaction/body/FIToFICstmrDrctDbt/DrctDbtTxInf/RmtInf/Remark"));
			}else {
				drcrFlg="";
			}

			map.put("drcrFlg", drcrFlg);
			pInfo = pInfo.length() > 510 ? pInfo.substring(0,509): pInfo;
			map.put("pInfo", pInfo);
			//借贷记报文的TxId格式不一样
			map.put("cpfsSeqNo",StringUtils.isNotEmpty((String)map.get("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId"))?(String)map.get("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId"):(String)map.get("/transaction/body/FIToFICstmrDrctDbt/GrpHdr/MsgId"));
			map.put("xSeqNo",StringUtils.isNotEmpty((String)map.get("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId"))?(String)map.get("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId"):(String)map.get("/transaction/body/FIToFICstmrDrctDbt/GrpHdr/MsgId"));
			map.put("chlSeqNo",StringUtils.isNotEmpty((String)map.get("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId"))?(String)map.get("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId"):(String)map.get("/transaction/body/FIToFICstmrDrctDbt/GrpHdr/MsgId"));
			map.put("pNo", "1");
			map.put("chkASta", StatEnum.CHKASTA_NOT_START.getCode());
			map.put("cpfsD",map.get("cpfsSeqNo").toString().substring(0,8));//渠道日期
			//20191023不需要登记此日期
			//map.put("clrgD",map.get("cpfsSeqNo").toString().substring(0,8));
			map.put("xDirn", TAbEnum.XDirn_In.getCode());//12前置到通道
			map.put("bizSta",StatEnum.BIZSTA_ING.getCode());//往账进来刚开始都是：02处理中
			map.put("pCId",SysEcodeEnum.NCS.getCode());//NCS
			map.put("bizSysId",sndAppCd);
			map.put("sndSysId",sndAppCd);
			map.put("shardingId",map.get("/transaction/header/msg/sndMbrCd"));
			map.put("acqOrgId",map.get("/transaction/header/msg/sndMbrCd"));
			map.put("rcvSysId",SysEcodeEnum.NCS.getCode());//NCS
			map.put("chkASta",StatEnum.CHKASTA_NOT_START.getCode());//未对账
			map.put("pTms",StatEnum.PAY_TIMES_ONE.getCode());
			map.put("creTm",DateUtil.getTimestamp(new Date()));
			LOGGER.info("NCSNstrASrvBean插表参数map为：[{}]" , map.toString());
		}catch (Throwable e){
			throw new BaseException(RespCd.NCPO0101,e,"NCS往账报文解包异常");
		}
		return map;
		
	}
		

}